/**
 * Search page tests
 */

import React from 'react';
import { render, screen, waitFor, fireEvent, change } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from 'react-query';
import Search from '../../src/pages/Search';

// Mock API services
jest.mock('../../src/services/api', () => ({
  searchApi: {
    search: jest.fn(),
    getSuggestions: jest.fn(),
    getComponents: jest.fn(),
    getTokens: jest.fn(),
  },
}));

// Import mocked APIs for use in tests
const { searchApi } = require('../../src/services/api');

// Mock Antd components
jest.mock('antd', () => ({
  Row: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Col: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Card: ({ children, title }: { children: React.ReactNode; title?: string }) => (
    <div>
      <h2>{title}</h2>
      <div>{children}</div>
    </div>
  ),
  Input: ({
    placeholder,
    value,
    onChange,
    onPressEnter,
    suffix
  }: {
    placeholder: string;
    value?: string;
    onChange?: (e: any) => void;
    onPressEnter?: () => void;
    suffix?: React.ReactNode;
  }) => (
    <input
      placeholder={placeholder}
      value={value}
      onChange={onChange}
      onKeyDown={(e) => e.key === 'Enter' && onPressEnter?.()}
      data-testid="search-input"
    />
  ),
  Button: ({
    children,
    onClick,
    loading,
    type,
    icon
  }: {
    children: React.ReactNode;
    onClick?: () => void;
    loading?: boolean;
    type?: string;
    icon?: React.ReactNode;
  }) => (
    <button
      onClick={onClick}
      disabled={loading}
      data-testid={type === 'primary' ? 'search-button' : 'filter-button'}
    >
      {loading ? 'Loading...' : children}
    </button>
  ),
  Select: ({
    children,
    placeholder,
    value,
    onChange,
    mode,
    allowClear
  }: any) => (
    <select
      value={value}
      onChange={(e) => onChange(e.target.value)}
      multiple={mode === 'multiple'}
      data-testid="select-filter"
    >
      {placeholder && <option value="">{placeholder}</option>}
      {children}
    </select>
  ),
  Checkbox: ({
    checked,
    onChange,
    children
  }: {
    checked: boolean;
    onChange: (e: any) => void;
    children: React.ReactNode
  }) => (
    <label>
      <input
        type="checkbox"
        checked={checked}
        onChange={onChange}
      />
      {children}
    </label>
  ),
  Table: ({
    columns,
    dataSource,
    loading,
    pagination
  }: any) => (
    <div>
      {loading && <div>Loading table...</div>}
      <table>
        <thead>
          <tr>
            {columns.map((col: any) => (
              <th key={col.key}>{col.title}</th>
            ))}
          </tr>
        </thead>
        <tbody>
          {dataSource.map((row: any, index: number) => (
            <tr key={index}>
              {columns.map((col: any) => (
                <td key={col.key}>
                  {col.render ? col.render(row[col.dataIndex], row) : row[col.dataIndex]}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
      {pagination && <div>Pagination controls</div>}
    </div>
  ),
  Tag: ({ children, color }: { children: React.ReactNode; color?: string }) => (
    <span style={{ backgroundColor: color }}>{children}</span>
  ),
  Empty: ({ description }: { description: string }) => (
    <div>{description}</div>
  ),
  Spin: ({ children, spinning }: { children: React.ReactNode; spinning: boolean }) => (
    <div>{spinning ? 'Loading...' : children}</div>
  ),
  Alert: ({ message, type }: { message: string; type: string }) => (
    <div className={`alert-${type}`}>{message}</div>
  ),
  AutoComplete: ({
    options,
    value,
    onChange,
    onSelect,
    placeholder
  }: any) => (
    <input
      placeholder={placeholder}
      value={value}
      onChange={(e) => onChange(e.target.value)}
      data-testid="autocomplete-input"
    />
  ),
  Space: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
  Typography: {
    Title: ({ children }: { children: React.ReactNode }) => <h2>{children}</h2>,
    Text: ({ children }: { children: React.ReactNode }) => <span>{children}</span>,
    Paragraph: ({ children }: { children: React.ReactNode }) => <p>{children}</p>,
  },
  Tag: ({ children, color }: { children: React.ReactNode; color?: string }) => (
    <span className={`tag tag-${color}`}>{children}</span>
  ),
  Avatar: ({ children }: { children: React.ReactNode }) => <div className="avatar">{children}</div>,
  List: ({ children, dataSource, renderItem }: any) => (
    <ul className="list">
      {dataSource?.map((item: any, index: number) => (
        <li key={index}>{renderItem ? renderItem(item) : item}</li>
      ))}
    </ul>
  ),
  Pagination: ({ current, total, onChange }: any) => (
    <div className="pagination">
      <button onClick={() => onChange(current - 1)} disabled={current <= 1}>Previous</button>
      <span>{current} / {Math.ceil(total / 10)}</span>
      <button onClick={() => onChange(current + 1)} disabled={current >= Math.ceil(total / 10)}>Next</button>
    </div>
  ),
  Collapse: ({ children }: { children: React.ReactNode }) => <div className="collapse">{children}</div>,
  Form: Object.assign(
    ({ children }: { children: React.ReactNode }) => <form>{children}</form>,
    {
      useForm: () => [{
        setFieldsValue: jest.fn(),
        getFieldsValue: jest.fn(),
        validateFields: jest.fn(),
        resetFields: jest.fn(),
      }]
    }
  ),
  DatePicker: ({ onChange }: any) => <input type="date" onChange={(e) => onChange(e.target.value)} />,
  Divider: () => <hr />,
  Empty: ({ description }: { description?: string }) => <div>{description || 'No data'}</div>,
  Spin: ({ children }: { children: React.ReactNode }) => <div>Loading... {children}</div>,
  Alert: ({ message, type }: { message: string; type: string }) => (
    <div className={`alert-${type}`}>{message}</div>
  ),
  Tooltip: ({ children }: { children: React.ReactNode }) => <div className="tooltip">{children}</div>,
  Badge: ({ children, count }: { children: React.ReactNode; count?: number }) => (
    <span className="badge">
      {children}
      {count && <span className="badge-count">{count}</span>}
    </span>
  ),
  Dropdown: ({ children, overlay }: { children: React.ReactNode; overlay: React.ReactNode }) => (
    <div className="dropdown">
      {children}
      {overlay}
    </div>
  ),
  Menu: ({ children }: { children: React.ReactNode }) => <ul className="menu">{children}</ul>,
  Option: ({ children, value }: { children: React.ReactNode; value: string }) => <option value={value}>{children}</option>,
}));

const createTestQueryClient = () => new QueryClient({
  defaultOptions: {
    queries: { retry: false },
    mutations: { retry: false },
  },
});

describe('Search Page', () => {
  let queryClient: QueryClient;

  beforeEach(() => {
    queryClient = createTestQueryClient();
    jest.clearAllMocks();
  });

  const renderSearchPage = () => {
    return render(
      <QueryClientProvider client={queryClient}>
        <Search />
      </QueryClientProvider>
    );
  };

  it('renders search page title and input', () => {
    renderSearchPage();

    expect(screen.getByText(/搜索遥测点|Search Telemetry Points/i)).toBeInTheDocument();
    expect(screen.getByTestId('search-input')).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/输入搜索关键词|Enter search keywords/i)).toBeInTheDocument();
  });

  it('performs search when user types and presses Enter', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [
        {
          id: 1,
          name: 'TestMetric',
          type: 'histogram',
          component: 'TestComponent',
          description: 'Test description',
          match_score: 0.95,
          match_fields: ['name']
        }
      ],
      total: 1,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(searchApi.search).toHaveBeenCalledWith(
        {
          query: 'test',
          filters: {},
          include_ukm: true,
          include_uma: true,
          include_enums: true,
          team_filter: undefined,
          component_filter: undefined
        },
        { page: 1, page_size: 10 }
      );
    });
  });

  it('performs search when search button is clicked', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [],
      total: 0,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');

    const searchButton = screen.getByTestId('search-button');
    fireEvent.click(searchButton);

    await waitFor(() => {
      expect(searchApi.search).toHaveBeenCalled();
    });
  });

  it('displays search results in table', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [
        {
          id: 1,
          name: 'TestMetric1',
          type: 'histogram',
          component: 'TestComponent1',
          description: 'Test description 1',
          match_score: 0.95,
          match_fields: ['name']
        },
        {
          id: 2,
          name: 'TestMetric2',
          type: 'enum',
          component: 'TestComponent2',
          description: 'Test description 2',
          match_score: 0.85,
          match_fields: ['description']
        }
      ],
      total: 2,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(screen.getByText('TestMetric1')).toBeInTheDocument();
      expect(screen.getByText('TestMetric2')).toBeInTheDocument();
    });
  });

  it('shows empty state when no results found', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [],
      total: 0,
      query: 'nonexistent',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'nonexistent');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(screen.getByText(/No results found|未找到结果/i)).toBeInTheDocument();
    });
  });

  it('displays search suggestions as user types', async () => {
    // searchApi already imported above
    searchApi.getSuggestions.mockResolvedValue({
      success: true,
      suggestions: ['test.metric', 'test.memory', 'test.performance']
    });

    renderSearchPage();

    const autocompleteInput = screen.getByTestId('autocomplete-input');
    if (autocompleteInput) {
      await userEvent.type(autocompleteInput, 'test');

      await waitFor(() => {
        expect(searchApi.getSuggestions).toHaveBeenCalledWith({ q: 'test', limit: 10 });
      });
    }
  });

  it('applies type filters correctly', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [],
      total: 0,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    // Find and select type filters
    const histogramCheckbox = screen.getByText(/histogram/i);
    const enumCheckbox = screen.getByText(/enum/i);

    fireEvent.click(histogramCheckbox);
    fireEvent.click(enumCheckbox);

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(searchApi.search).toHaveBeenCalledWith(
        expect.objectContaining({
          include_ukm: false, // Only UMA types selected
          include_uma: true,
          include_enums: true
        }),
        expect.any(Object)
      );
    });
  });

  it('applies component and team filters', async () => {
    // searchApi already imported above
    searchApi.getComponents.mockResolvedValue(['Component1', 'Component2']);
    searchApi.search.mockResolvedValue({
      success: true,
      data: [],
      total: 0,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    await waitFor(() => {
      expect(searchApi.getComponents).toHaveBeenCalled();
    });

    // Mock component selection (implementation dependent on actual UI)
    const componentSelect = screen.getByTestId('select-filter');
    if (componentSelect) {
      fireEvent.change(componentSelect, { target: { value: 'Component1' } });
    }

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(searchApi.search).toHaveBeenCalledWith(
        expect.objectContaining({
          component_filter: 'Component1'
        }),
        expect.any(Object)
      );
    });
  });

  it('handles pagination correctly', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [],
      total: 25, // More than page size
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(searchApi.search).toHaveBeenCalledWith(
        expect.any(Object),
        { page: 1, page_size: 10 }
      );
    });

    // Test page change (implementation dependent)
    // This would require finding and clicking pagination controls
  });

  it('displays loading state during search', async () => {
    // searchApi already imported above
    searchApi.search.mockImplementation(() => new Promise(resolve =>
      setTimeout(() => resolve({
        success: true,
        data: [],
        total: 0,
        query: 'test',
        page: 1,
        page_size: 10
      }), 100)
    ));

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    expect(screen.getByText('Loading...')).toBeInTheDocument();

    await waitFor(() => {
      expect(screen.queryByText('Loading...')).not.toBeInTheDocument();
    }, { timeout: 200 });
  });

  it('handles search errors gracefully', async () => {
    // searchApi already imported above
    searchApi.search.mockRejectedValue(new Error('Search failed'));

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(screen.getByText(/Search failed|搜索失败/i)).toBeInTheDocument();
    });
  });

  it('clears filters correctly', async () => {
    renderSearchPage();

    // Select some filters
    const histogramCheckbox = screen.getByText(/histogram/i);
    fireEvent.click(histogramCheckbox);

    // Find and click clear button if it exists
    const clearButton = screen.getByText(/Clear|清除/i);
    if (clearButton) {
      fireEvent.click(clearButton);

      // Verify filters are cleared
      expect(histogramCheckbox).not.toBeChecked();
    }
  });

  it('validates search query before submitting', async () => {
    renderSearchPage();

    // Try to search with empty query
    const searchInput = screen.getByTestId('search-input');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    // Should not make API call with empty query
    // searchApi already imported above
    expect(searchApi.search).not.toHaveBeenCalled();
  });

  it('displays match score in results', async () => {
    // searchApi already imported above
    searchApi.search.mockResolvedValue({
      success: true,
      data: [
        {
          id: 1,
          name: 'TestMetric',
          type: 'histogram',
          component: 'TestComponent',
          description: 'Test description',
          match_score: 0.95,
          match_fields: ['name']
        }
      ],
      total: 1,
      query: 'test',
      page: 1,
      page_size: 10
    });

    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    await userEvent.type(searchInput, 'test');
    fireEvent.keyDown(searchInput, { key: 'Enter' });

    await waitFor(() => {
      expect(screen.getByText(/95%|0.95/)).toBeInTheDocument();
    });
  });

  it('is accessible with proper keyboard navigation', async () => {
    renderSearchPage();

    const searchInput = screen.getByTestId('search-input');
    searchInput.focus();

    // Test tab navigation
    fireEvent.keyDown(searchInput, { key: 'Tab' });

    // Verify focus moves to next element
    expect(document.activeElement).not.toBe(searchInput);
  });
});